home *** CD-ROM | disk | FTP | other *** search
/ OpenGL Superbible (2nd Edition) / OpenGL SuperBible e2.iso / tools / FLTK-1.0.6 / src / Fl_Color_Chooser.cxx < prev    next >
Encoding:
C/C++ Source or Header  |  1999-03-07  |  12.6 KB  |  436 lines

  1. //
  2. // "$Id: Fl_Color_Chooser.cxx,v 1.7 1999/03/07 08:51:43 bill Exp $"
  3. //
  4. // Color chooser for the Fast Light Tool Kit (FLTK).
  5. //
  6. // Copyright 1998-1999 by Bill Spitzak and others.
  7. //
  8. // This library is free software; you can redistribute it and/or
  9. // modify it under the terms of the GNU Library General Public
  10. // License as published by the Free Software Foundation; either
  11. // version 2 of the License, or (at your option) any later version.
  12. //
  13. // This library is distributed in the hope that it will be useful,
  14. // but WITHOUT ANY WARRANTY; without even the implied warranty of
  15. // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  16. // Library General Public License for more details.
  17. //
  18. // You should have received a copy of the GNU Library General Public
  19. // License along with this library; if not, write to the Free Software
  20. // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307
  21. // USA.
  22. //
  23. // Please report all bugs and problems to "fltk-bugs@easysw.com".
  24. //
  25.  
  26. #include <FL/Fl.H>
  27. #include <FL/Fl_Color_Chooser.H>
  28. #include <FL/fl_draw.H>
  29. #include <FL/math.h>
  30. #include <stdio.h>
  31.  
  32. // Besides being a useful object on it's own, the Fl_Color_Chooser was
  33. // an attempt to make a complex composite object that could be easily
  34. // imbedded into a user interface.  If you wish to make complex objects
  35. // of your own, be sure to read this code.
  36.  
  37. // The function fl_color_chooser() creates a window containing a color
  38. // chooser and a few buttons and current-color indicators.  It is an
  39. // easier interface for simple programs that just need a color.
  40.  
  41. // The "hue box" can be a circle or rectilinear.
  42. // You get a circle by defining this:
  43. // #define CIRCLE 1
  44. // And the "hue box" can auto-update when the value changes
  45. // you get this by defining this:
  46. #define UPDATE_HUE_BOX 1
  47.  
  48. void Fl_Color_Chooser::hsv2rgb(
  49.     double H, double S, double V, double& r, double& g, double& b) {
  50.   if (S < 5.0e-6) {
  51.     r = g = b = V;
  52.   } else {
  53.     int i = (int)H;  
  54.     double f = H - (float)i;
  55.     double p1 = V*(1.0-S);
  56.     double p2 = V*(1.0-S*f);
  57.     double p3 = V*(1.0-S*(1.0-f));
  58.     switch (i) {
  59.     case 0: r = V;   g = p3;  b = p1;  break;
  60.     case 1: r = p2;  g = V;   b = p1;  break;
  61.     case 2: r = p1;  g = V;   b = p3;  break;
  62.     case 3: r = p1;  g = p2;  b = V;   break;
  63.     case 4: r = p3;  g = p1;  b = V;   break;
  64.     case 5: r = V;   g = p1;  b = p2;  break;
  65.     }
  66.   }
  67. }
  68.  
  69. void Fl_Color_Chooser::rgb2hsv(
  70.     double r, double g, double b, double& H, double& S, double& V) {
  71.   double maxv = r > g ? r : g; if (b > maxv) maxv = b;
  72.   V = maxv;
  73.   if (maxv>0) {
  74.     double minv = r < g ? r : g; if (b < minv) minv = b;
  75.     S = 1.0 - double(minv)/maxv;
  76.     if (maxv > minv) {
  77.       if (maxv == r) {H = (g-b)/double(maxv-minv); if (H<0) H += 6.0;}
  78.       else if (maxv == g) H = 2.0+(b-r)/double(maxv-minv);
  79.       else H = 4.0+(r-g)/double(maxv-minv);
  80.     }
  81.   }
  82. }
  83.  
  84. enum {M_RGB, M_BYTE, M_HEX, M_HSV}; // modes
  85. static Fl_Menu_Item mode_menu[] = {
  86.   {"rgb"},
  87.   {"byte"},
  88.   {"hex"},
  89.   {"hsv"},
  90.   {0}
  91. };
  92.  
  93. int Flcc_Value_Input::format(char* buf) {
  94.   Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent();
  95.   if (c->mode() == M_HEX) return sprintf(buf,"0x%02X", int(value()));
  96.   else return Fl_Valuator::format(buf);
  97. }
  98.  
  99. void Fl_Color_Chooser::set_valuators() {
  100.   switch (mode()) {
  101.   case M_RGB:
  102.     rvalue.range(0,1); rvalue.step(1,1000); rvalue.value(r_);
  103.     gvalue.range(0,1); gvalue.step(1,1000); gvalue.value(g_);
  104.     bvalue.range(0,1); bvalue.step(1,1000); bvalue.value(b_);
  105.     break;
  106.   case M_BYTE:
  107.   case M_HEX:
  108.     rvalue.range(0,255); rvalue.step(1); rvalue.value(int(255*r_+.5));
  109.     gvalue.range(0,255); gvalue.step(1); gvalue.value(int(255*g_+.5));
  110.     bvalue.range(0,255); bvalue.step(1); bvalue.value(int(255*b_+.5));
  111.     break;
  112.   case M_HSV:
  113.     rvalue.range(0,6); rvalue.step(1,1000); rvalue.value(hue_);
  114.     gvalue.range(0,1); gvalue.step(1,1000); gvalue.value(saturation_);
  115.     bvalue.range(0,1); bvalue.step(1,1000); bvalue.value(value_);
  116.     break;
  117.   }
  118. }
  119.  
  120. int Fl_Color_Chooser::rgb(double r, double g, double b) {
  121.   if (r == r_ && g == g_ && b == b_) return 0;
  122.   r_ = r; g_ = g; b_ = b;
  123.   double ph = hue_;
  124.   double ps = saturation_;
  125.   double pv = value_;
  126.   rgb2hsv(r,g,b,hue_,saturation_,value_);
  127.   set_valuators();
  128.   if (value_ != pv) {
  129. #ifdef UPDATE_HUE_BOX
  130.     huebox.damage(FL_DAMAGE_SCROLL);
  131. #endif
  132.     valuebox.damage(FL_DAMAGE_EXPOSE);}
  133.   if (hue_ != ph || saturation_ != ps) {
  134.     huebox.damage(FL_DAMAGE_EXPOSE); 
  135.     valuebox.damage(FL_DAMAGE_SCROLL);
  136.   }
  137.   return 1;
  138. }
  139.  
  140. int Fl_Color_Chooser::hsv(double h, double s, double v) {
  141.   h = fmod(h,6.0); if (h < 0.0) h += 6.0;
  142.   if (s < 0.0) s = 0.0; else if (s > 1.0) s = 1.0;
  143.   if (v < 0.0) v = 0.0; else if (v > 1.0) v = 1.0;
  144.   if (h == hue_ && s == saturation_ && v == value_) return 0;
  145.   double ph = hue_;
  146.   double ps = saturation_;
  147.   double pv = value_;
  148.   hue_ = h; saturation_ = s; value_ = v;
  149.   if (value_ != pv) {
  150. #ifdef UPDATE_HUE_BOX
  151.     huebox.damage(FL_DAMAGE_SCROLL);
  152. #endif
  153.     valuebox.damage(FL_DAMAGE_EXPOSE);}
  154.   if (hue_ != ph || saturation_ != ps) {
  155.     huebox.damage(FL_DAMAGE_EXPOSE); 
  156.     valuebox.damage(FL_DAMAGE_SCROLL);
  157.   }
  158.   hsv2rgb(h,s,v,r_,g_,b_);
  159.   set_valuators();
  160.   return 1;
  161. }
  162.  
  163. ////////////////////////////////////////////////////////////////
  164.  
  165. static void tohs(double x, double y, double& h, double& s) {
  166. #ifdef CIRCLE
  167.   x = 2*x-1;
  168.   y = 1-2*y;
  169.   s = sqrt(x*x+y*y); if (s > 1.0) s = 1.0;
  170.   h = (3.0/M_PI)*atan2(y,x);
  171.   if (h<0) h += 6.0;
  172. #else
  173.   h = fmod(6.0*x,6.0); if (h < 0.0) h += 6.0;
  174.   s = 1.0-y; if (s < 0.0) s = 0.0; else if (s > 1.0) s = 1.0;
  175. #endif
  176. }
  177.  
  178. int Flcc_HueBox::handle(int e) {
  179.   static double ih, is;
  180.   Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent();
  181.   switch (e) {
  182.   case FL_PUSH:
  183.     ih = c->hue();
  184.     is = c->saturation();
  185.   case FL_DRAG: {
  186.     double Xf, Yf, H, S;
  187.     Xf = (Fl::event_x()-x()-Fl::box_dx(box()))/double(w()-Fl::box_dw(box()));
  188.     Yf = (Fl::event_y()-y()-Fl::box_dy(box()))/double(h()-Fl::box_dh(box()));
  189.     tohs(Xf, Yf, H, S);
  190.     if (fabs(H-ih) < 3*6.0/w()) H = ih;
  191.     if (fabs(S-is) < 3*1.0/h()) S = is;
  192.     if (Fl::event_state(FL_CTRL)) H = ih;
  193.     if (c->hsv(H, S, c->value())) c->do_callback();
  194.     } return 1;
  195.   default:
  196.     return 0;
  197.   }
  198. }
  199.  
  200. static void generate_image(void* vv, int X, int Y, int W, uchar* buf) {
  201.   Flcc_HueBox* v = (Flcc_HueBox*)vv;
  202.   int iw = v->w()-Fl::box_dw(v->box());
  203.   double Yf = double(Y)/(v->h()-Fl::box_dh(v->box()));
  204. #ifdef UPDATE_HUE_BOX
  205.   const double V = ((Fl_Color_Chooser*)(v->parent()))->value();
  206. #else
  207.   const double V = 1.0;
  208. #endif
  209.   for (int x = X; x < X+W; x++) {
  210.     double Xf = double(x)/iw;
  211.     double H,S; tohs(Xf,Yf,H,S);
  212.     double r,g,b;
  213.     Fl_Color_Chooser::hsv2rgb(H,S,V,r,g,b);
  214.     *buf++ = uchar(255*r+.5);
  215.     *buf++ = uchar(255*g+.5);
  216.     *buf++ = uchar(255*b+.5);
  217.   }
  218. }
  219.  
  220. void Flcc_HueBox::draw() {
  221.   if (damage()&FL_DAMAGE_ALL) draw_box();
  222.   int x1 = x()+Fl::box_dx(box());
  223.   int y1 = y()+Fl::box_dy(box());
  224.   int w1 = w()-Fl::box_dw(box());
  225.   int h1 = h()-Fl::box_dh(box());
  226.   if (damage() == FL_DAMAGE_EXPOSE) fl_clip(x1+px,y1+py,6,6);
  227.   fl_draw_image(generate_image, this, x1, y1, w1, h1);
  228.   if (damage() == FL_DAMAGE_EXPOSE) fl_pop_clip();
  229.   Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent();
  230. #ifdef CIRCLE
  231.   int X = int(.5*(cos(c->hue()*(M_PI/3.0))*c->saturation()+1) * (w1-6));
  232.   int Y = int(.5*(1-sin(c->hue()*(M_PI/3.0))*c->saturation()) * (h1-6));
  233. #else
  234.   int X = int(c->hue()/6.0*(w1-6));
  235.   int Y = int((1-c->saturation())*(h1-6));
  236. #endif
  237.   if (X < 0) X = 0; else if (X > w1-6) X = w1-6;
  238.   if (Y < 0) Y = 0; else if (Y > h1-6) Y = h1-6;
  239.   //  fl_color(c->value()>.75 ? FL_BLACK : FL_WHITE);
  240.   draw_box(FL_UP_BOX,x1+X,y1+Y,6,6,FL_GRAY);
  241.   px = X; py = Y;
  242. }
  243.  
  244. ////////////////////////////////////////////////////////////////
  245.  
  246. int Flcc_ValueBox::handle(int e) {
  247.   static double iv;
  248.   Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent();
  249.   switch (e) {
  250.   case FL_PUSH:
  251.     iv = c->value();
  252.   case FL_DRAG: {
  253.     double Yf;
  254.     Yf = 1-(Fl::event_y()-y()-Fl::box_dy(box()))/double(h()-Fl::box_dh(box()));
  255.     if (fabs(Yf-iv)<(3*1.0/h())) Yf = iv;
  256.     if (c->hsv(c->hue(),c->saturation(),Yf)) c->do_callback();
  257.     } return 1;
  258.   default:
  259.     return 0;
  260.   }
  261. }
  262.  
  263. static double tr, tg, tb;
  264. static void generate_vimage(void* vv, int X, int Y, int W, uchar* buf) {
  265.   Flcc_ValueBox* v = (Flcc_ValueBox*)vv;
  266.   double Yf = 255*(1.0-double(Y)/(v->h()-Fl::box_dh(v->box())));
  267.   uchar r = uchar(tr*Yf+.5);
  268.   uchar g = uchar(tg*Yf+.5);
  269.   uchar b = uchar(tb*Yf+.5);
  270.   for (int x = X; x < X+W; x++) {
  271.     *buf++ = r; *buf++ = g; *buf++ = b;
  272.   }
  273. }
  274.  
  275. void Flcc_ValueBox::draw() {
  276.   if (damage()&FL_DAMAGE_ALL) draw_box();
  277.   Fl_Color_Chooser* c = (Fl_Color_Chooser*)parent();
  278.   c->hsv2rgb(c->hue(),c->saturation(),1.0,tr,tg,tb);
  279.   int x1 = x()+Fl::box_dx(box());
  280.   int y1 = y()+Fl::box_dy(box());
  281.   int w1 = w()-Fl::box_dw(box());
  282.   int h1 = h()-Fl::box_dh(box());
  283.   if (damage() == FL_DAMAGE_EXPOSE) fl_clip(x1,y1+py,w1,6);
  284.   fl_draw_image(generate_vimage, this, x1, y1, w1, h1);
  285.   if (damage() == FL_DAMAGE_EXPOSE) fl_pop_clip();
  286.   int Y = int((1-c->value()) * (h1-6));
  287.   if (Y < 0) Y = 0; else if (Y > h1-6) Y = h1-6;
  288.   draw_box(FL_UP_BOX,x1,y1+Y,w1,6,FL_GRAY);
  289.   py = Y;
  290. }
  291.  
  292. ////////////////////////////////////////////////////////////////
  293.  
  294. void Fl_Color_Chooser::rgb_cb(Fl_Widget* o, void*) {
  295.   Fl_Color_Chooser* c = (Fl_Color_Chooser*)(o->parent());
  296.   double r = c->rvalue.value();
  297.   double g = c->gvalue.value();
  298.   double b = c->bvalue.value();
  299.   if (c->mode() == M_HSV) {
  300.     if (c->hsv(r,g,b)) c->do_callback();
  301.     return;
  302.   }
  303.   if (c->mode() != M_RGB) {
  304.     r = r/255;
  305.     g = g/255;
  306.     b = b/255;
  307.   }
  308.   if (c->rgb(r,g,b)) c->do_callback();
  309. }
  310.  
  311. void Fl_Color_Chooser::mode_cb(Fl_Widget* o, void*) {
  312.   Fl_Color_Chooser* c = (Fl_Color_Chooser*)(o->parent());
  313.   // force them to redraw even if value is the same:
  314.   c->rvalue.value(-1);
  315.   c->gvalue.value(-1);
  316.   c->bvalue.value(-1);
  317.   c->set_valuators();
  318. }
  319.  
  320. ////////////////////////////////////////////////////////////////
  321.  
  322. Fl_Color_Chooser::Fl_Color_Chooser(int X, int Y, int W, int H, const char* L)
  323.   : Fl_Group(0,0,180,100,L),
  324.     huebox(0,0,100,100),
  325.     valuebox(100,0,20,100),
  326.     choice(120,0,60,20),
  327.     rvalue(120,20,60,25),
  328.     gvalue(120,45,60,25),
  329.     bvalue(120,70,60,25),
  330.     resize_box(0,95,100,5)
  331. {
  332.   end();
  333.   resizable(resize_box);
  334.   resize(X,Y,W,H);
  335.   r_ = g_ = b_ = 0;
  336.   hue_ = 0.0;
  337.   saturation_ = 0.0;
  338.   value_ = 0.0;
  339.   huebox.box(FL_DOWN_FRAME);
  340.   valuebox.box(FL_DOWN_FRAME);
  341.   choice.menu(mode_menu);
  342.   set_valuators();
  343.   rvalue.callback(rgb_cb);
  344.   gvalue.callback(rgb_cb);
  345.   bvalue.callback(rgb_cb);
  346.   choice.callback(mode_cb);
  347.   choice.box(FL_THIN_UP_BOX);
  348.   choice.textfont(FL_HELVETICA_BOLD_ITALIC);
  349. }
  350.  
  351. ////////////////////////////////////////////////////////////////
  352. // fl_color_chooser():
  353.  
  354. #include <FL/Fl_Window.H>
  355. #include <FL/Fl_Box.H>
  356. #include <FL/Fl_Return_Button.H>
  357.  
  358. class ColorChip : public Fl_Widget {
  359.   void draw();
  360. public:
  361.   uchar r,g,b;
  362.   ColorChip(int X, int Y, int W, int H) : Fl_Widget(X,Y,W,H) {
  363.     box(FL_ENGRAVED_FRAME);}
  364. };
  365.  
  366. void ColorChip::draw() {
  367.   if (damage()&FL_DAMAGE_ALL) draw_box();
  368.   fl_rectf(x()+Fl::box_dx(box()),
  369.        y()+Fl::box_dy(box()),
  370.        w()-Fl::box_dw(box()),
  371.        h()-Fl::box_dh(box()),r,g,b);
  372. }
  373.  
  374. static void chooser_cb(Fl_Object* o, void* vv) {
  375.   Fl_Color_Chooser* c = (Fl_Color_Chooser*)o;
  376.   ColorChip* v = (ColorChip*)vv;
  377.   v->r = uchar(255*c->r()+.5);
  378.   v->g = uchar(255*c->g()+.5);
  379.   v->b = uchar(255*c->b()+.5);
  380.   v->damage(FL_DAMAGE_EXPOSE);
  381. }
  382.  
  383. extern const char* fl_ok;
  384. extern const char* fl_cancel;
  385.  
  386. int fl_color_chooser(const char* name, double& r, double& g, double& b) {
  387.   Fl_Window window(210,165,name);
  388.   Fl_Color_Chooser chooser(5, 5, 200, 95);
  389.   ColorChip ok_color(5, 105, 95, 30);
  390.   Fl_Return_Button ok_button(5, 135, 95, 25, fl_ok);
  391.   ColorChip cancel_color(110, 105, 95, 30);
  392.   cancel_color.r = uchar(255*r+.5); ok_color.r = cancel_color.r;
  393.   ok_color.g = cancel_color.g = uchar(255*g+.5);
  394.   ok_color.b = cancel_color.b = uchar(255*b+.5);
  395.   Fl_Button cancel_button(110, 135, 95, 25, fl_cancel);
  396.   window.resizable(chooser);
  397.   chooser.rgb(r,g,b);
  398.   chooser.callback(chooser_cb, &ok_color);
  399.   window.end();
  400.   window.set_modal();
  401.   window.hotspot(window);
  402.   window.show();
  403.   while (window.shown()) {
  404.     Fl::wait();
  405.     for (;;) {
  406.       Fl_Widget* o = Fl::readqueue();
  407.       if (!o) break;
  408.       if (o == &ok_button) {
  409.     r = chooser.r();
  410.     g = chooser.g();
  411.     b = chooser.b();
  412.     return 1;
  413.       }
  414.       if (o == &window || o == &cancel_button) return 0;
  415.     }
  416.   }
  417.   return 0;
  418. }
  419.  
  420. int fl_color_chooser(const char* name, uchar& r, uchar& g, uchar& b) {
  421.   double dr = r/255.0;
  422.   double dg = g/255.0;
  423.   double db = b/255.0;
  424.   if (fl_color_chooser(name,dr,dg,db)) {
  425.     r = uchar(255*dr+.5);
  426.     g = uchar(255*dg+.5);
  427.     b = uchar(255*db+.5);
  428.     return 1;
  429.   }
  430.   return 0;
  431. }
  432.  
  433. //
  434. // End of "$Id: Fl_Color_Chooser.cxx,v 1.7 1999/03/07 08:51:43 bill Exp $".
  435. //
  436.